package cc.rengu.igas.opms.core.service.trans.quickpay;

import cc.rengu.igas.opms.common.enums.FeeTypeEnum;
import cc.rengu.igas.opms.common.enums.RespCodeEnum;
import cc.rengu.igas.opms.common.enums.SignTokenTypeEnum;
import cc.rengu.igas.opms.core.service.base.PayService;
import cc.rengu.igas.opms.facade.request.StagePayRequest;
import cc.rengu.igas.opms.facade.response.StagePayResponse;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.igas.share.common.constant.UserSessionConstant;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.model.UserInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.UserService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.igas.share.core.realize.impl.UserServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.SignAcctInfoMapper;
import cc.rengu.oltp.service.common.dao.UserOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.SignAcctInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.UserOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.realize.*;
import cc.rengu.oltp.service.realize.impl.*;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSONObject;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 分期支付(手机扫码分期也走该服务)
 *
 * @author keyi
 * @date 2020/3/27.
 */

public class StagePayService extends PayService implements TransCustomImpl {

    @Override
    protected Object bizBeforeCust() throws Exception {
        StagePayRequest stagePayRequest = new StagePayRequest();
        ConvertUtil.convertOutput(stagePayRequest);
        return stagePayRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        StagePayRequest stagePayRequest = (StagePayRequest) request;
        String instId = stagePayRequest.getHeader().getInstId();
        String txnNum = stagePayRequest.getHeader().getTxnNum();
        String bizType = stagePayRequest.getHeader().getBizType();
        String sessionId = stagePayRequest.getHeader().getSession();
        String userId = stagePayRequest.getUserId();
        String signToken = stagePayRequest.getSignToken();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        String isBuyCouponTrans = AppParamConstant.NO;

        //用户会话校验并校验用户支付密码
        UserService userService = new UserServiceImpl();
        UserInfo userInfo = userService.getUserInfo(instId, userId, sessionId);
        if (null == userInfo) {
            rglog.error("获取用户信息失败!");
            throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
        }
        boolean checkResult = userService.checkUserPayPassword(instId, userId, stagePayRequest.getOrderAmt(), stagePayRequest.getPassword());
        if (!checkResult) {
            rglog.error("用户支付密码校验失败!");
            throw new BizException(RespCodeEnum.USER_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_PASSWORD_ERROR.getRespDesc());
        }
        String signInst = userService.getUserSignInst();

        //检查用户签约信息
        SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
        SignAcctInfo signAcctInfo = signAcctInfoMapper.selectSignAcctInfoByPrimaryKey(instId, SignTokenTypeEnum.BANK_QUICK_PAY.getSignTypeCode(), signToken, signInst);
        if (null == signAcctInfo) {
            rglog.info("本行快捷支付签约数据不存在或已解约或账号不一致,signToken:<{}>", stagePayRequest.getSignToken());
            throw new BizException(RespCodeEnum.INVALID_SIGNID_ERROR.getRespCode(), RespCodeEnum.INVALID_SIGNID_ERROR.getRespDesc());
        } else if (!AppParamConstant.YES.equals(signAcctInfo.getSignStatus())) {
            rglog.error("协议号<{}>,账号<{}>已解约", signAcctInfo.getSignToken(), signAcctInfo.getSignAcctNo());
            throw new BizException(RespCodeEnum.SIGN_RESCISSION.getRespCode(), RespCodeEnum.SIGN_RESCISSION.getRespDesc());
        } else if (!signAcctInfo.getSignAcctNo().endsWith(stagePayRequest.getAcctNo())) {
            rglog.error("支付卡号尾号<{}>,与签约账号<{}>不一致", stagePayRequest.getAcctNo(), signAcctInfo.getSignAcctNo());
            throw new BizException(RespCodeEnum.USER_INFO_MISMATCH.getRespCode(), RespCodeEnum.USER_INFO_MISMATCH.getRespDesc());
        }
        GlobalTransUtil.setCacheValue(TransCacheConstant.SIGN_ACCT_INFO, signAcctInfo);

        //获取订单信息
        OrderService orderService = new OrderServiceImpl();
        OrderInfo orderInfo = orderService.selectOrderInfoByUserOrderId(instId, stagePayRequest.getUserOrderId());
        if (null == orderInfo) {
            rglog.error("订单信息不存在!");
            throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }
        UserOrderInfo userOrderInfo = orderInfo.getUserOrderInfo();
        //更新用户订单中的订单信息
        userOrderInfo.setOrderDesc(stagePayRequest.getOrderDesc());
        userOrderInfo.setTxnNum(txnNum);
        userOrderInfo.setBizType(bizType);
        userOrderInfo.setSysSeqNum(sysSeqNum);
        userOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        userOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        userOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        //用户限额检查
        String cardPayAmt = userOrderInfo.getNeedPayAmt();
        if (stagePayRequest.getCouponInfo() != null && stagePayRequest.getCouponInfo().getDiscountAmt() != null) {
            cardPayAmt = AmountUtil.subtraction(cardPayAmt, stagePayRequest.getCouponInfo().getDiscountAmt());
        }
        userOrderInfo.setRealPayAmt(cardPayAmt);
        checkResult = userService.checkUserTransLimit(instId, userId, txnNum, stagePayRequest.getOrderAmt(), LimitTypeEnum.CASHIER.getLimitType());
        if (!checkResult) {
            rglog.error("用户<{}>支付限额超限!", userId);
            throw new BizException(RespCodeEnum.OPM_OVER_AMT_LIMIT.getRespCode(), RespCodeEnum.OPM_OVER_AMT_LIMIT.getRespDesc());
        }
        //分期支付不支持合并订单支付
        List<MchntOrderInfo> mchntOrderInfoList = orderInfo.getMchntOrderInfoList();
        if (mchntOrderInfoList.size() > 1) {
            rglog.info("分期支付不支持合并订单支付，mchntOrderInfoSize:<{}>", mchntOrderInfoList.size());
            throw new BizException(RespCodeEnum.ORDER_NOT_ALLOW_PAY.getRespCode(), RespCodeEnum.ORDER_NOT_ALLOW_PAY.getRespDesc());
        }
        List<MchntOrderDetail> mchntOrderDetailList = orderInfo.getMchntOrderDetailList();
        if (null != mchntOrderDetailList && !mchntOrderDetailList.isEmpty()) {
            mchntOrderDetailList.forEach(item -> item.setSysSeqNum(sysSeqNum));
        }

        //购买卡券不支持使用优惠券
        if ("00".equals(mchntOrderInfoList.get(0).getBizSceneType()) || "02".equals(mchntOrderInfoList.get(0).getBizSceneType())) {
            isBuyCouponTrans = AppParamConstant.YES;
            GlobalTransUtil.setCacheValue(TransCacheConstant.BUY_COUPON_TRANS_FLAG, AppParamConstant.YES);
            if (stagePayRequest.getCouponInfo() != null && stagePayRequest.getCouponInfo().getDiscountId() != null) {
                rglog.error("购买卡券交易不支持使用卡券");
                throw new BizException(RespCodeEnum.ORDER_NOT_ALLOW_PAY.getRespCode(), RespCodeEnum.ORDER_NOT_ALLOW_PAY.getRespDesc());
            }
        }
        //判断是否有上送卡卷,若有上送，则将优惠卷放到交易缓存中
        if (stagePayRequest.getCouponInfo() != null && stagePayRequest.getCouponInfo().getDiscountId() != null) {
            GlobalTransUtil.setCacheValue(TransCacheConstant.COUPON_INFO, stagePayRequest.getCouponInfo());
        }
        //商户权限及限额检查
        MchntService mchntService = new MchntServiceImpl();
        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
            /*获取商户基本信息表*/
            MchntInfo mchntInfo = mchntService.getMchntInfo(instId, mchntOrderInfo.getMchntNo());
            /*判断商户是否是独立清算的门店商户*/
            if ("11".equals(mchntInfo.getMchntType()) && AppParamConstant.NO.equals(mchntInfo.getIndependentDataFlag())) {
                rglog.debug("非独立维护资料的门店商户商户订单表记录其连锁商户号");
                mchntOrderInfo.setChainMchntNo(mchntInfo.getChainMchntNo());
                mchntInfo = mchntService.getMchntInfo(instId, mchntInfo.getChainMchntNo());
            }
            /* 商户交易权限检查 */
            checkResult = mchntService.checkMchntAuth(instId, mchntOrderInfo.getMchntNo(), null, txnNum, bizType, signAcctInfo.getSignAcctType());
            if (!checkResult) {
                rglog.error("商户<{}>无此交易权限!", mchntOrderInfo.getMchntNo());
                throw new BizException(RespCodeEnum.NOT_SURP_TRANS_TYPE_ERROR.getRespCode(), RespCodeEnum.NOT_SURP_TRANS_TYPE_ERROR.getRespDesc());
            }
            /* 商户限额校验 */
            int limitFlag = mchntService.checkMchntTransLimit(instId, mchntOrderInfo.getRealSettleAmt(), LimitAcctTypeEnum.ALL, mchntOrderInfo.getMchntNo(), null, txnNum);
            if (limitFlag == 2 || limitFlag == 3) {
                rglog.error("商户金额超限");
                throw new BizException(RespCodeEnum.MCHNT_AMT_OVER.getRespCode(), RespCodeEnum.MCHNT_AMT_OVER.getRespDesc());
            } else if (limitFlag == 1) {
                rglog.debug("商户贷记卡超限，交易上送不支持贷记卡标识");
                xmlTreeUtil.setXmlTreeStringValue("limitPay", "no_credit");
            }
            /* 商户订单信息赋值 */
            mchntOrderInfo.setBizProdCode(txnInfo.getSrcTxnAuthCfg().getBizProdCode());
            mchntOrderInfo.setTxnNum(txnNum);
            mchntOrderInfo.setBizType(bizType);
            mchntOrderInfo.setSysSeqNum(sysSeqNum);
            mchntOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
            mchntOrderInfo.setMchntDiscountFee("0.00");
            mchntOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
            mchntOrderInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            if (stagePayRequest.getCouponInfo() != null && stagePayRequest.getCouponInfo().getDiscountId() != null) {
                mchntOrderInfo.setRealSettleFlag(AppParamConstant.NO);
            } else {
                String realSettleFlag = mchntService.getRealSettleFlag(mchntInfo.getMchntNo(), txnInfo.getSrcTxnAuthCfg().getBizProdCode(), mchntOrderInfo.getBizSceneType(), mchntOrderInfo.getRealSettleAmt());
                mchntOrderInfo.setRealSettleFlag(realSettleFlag);
                if (AppParamConstant.YES.equals(mchntOrderInfo.getRealSettleFlag())) {
                    mchntOrderInfo.setRealSettleType("99");
                }
            }
        }

        //非购买卡卷交易计算商户手续费
        if (AppParamConstant.NO.equals(isBuyCouponTrans)) {
            String feeType;
            if (AcctTypeEnum.BANK_CREDIT.getAcctType().equals(signAcctInfo.getSignAcctType())) {
                feeType = FeeTypeEnum.BANK_CR_CARD.getFeeType();
            } else if (AcctTypeEnum.BANK_DEBIT.getAcctType().equals(signAcctInfo.getSignAcctType())) {
                feeType = FeeTypeEnum.BANK_DR_CARD.getFeeType();
            } else if (AcctTypeEnum.OTHER_DEBIT.getAcctType().equals(signAcctInfo.getSignAcctType())) {
                feeType = FeeTypeEnum.OTHER_BANK_DR_CARD.getFeeType();
            } else {
                feeType = FeeTypeEnum.OTHER_BANK_CR_CARD.getFeeType();
            }
            mchntService.calcMchntFee(mchntOrderInfoList, feeType);
        }

        //更新订单信息
        if (!orderService.updateOrderInfo(userOrderInfo, mchntOrderInfoList)) {
            rglog.error("更新订单信息失败");
            throw new BizException(RespCodeEnum.UPDATE_ORDER_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_ERROR.getRespDesc());
        }

        //调用通道接口
        if (null == txnInfo.getChannelCallCfgList() || txnInfo.getChannelCallCfgList().isEmpty()) {
            rglog.error("<{}-{}>交易未配置交易通道服务调用配置信息！", txnInfo.getSrcTxnAuthCfg().getTxnNum(), txnInfo.getSrcTxnAuthCfg().getTxnName());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList().stream().filter(item ->
                item.getCallIndex().equals(ChannelBaseService.FIRST_CHANNEL_CALL_INDEX)).collect(Collectors.toList());
        ChannelCallCfg channelCallCfg = channelCallSceneDiscern(stagePayRequest, channelCallCfgList);
        Class channelClasz = Class.forName(channelCallCfg.getCallChannelImpl());
        ChannelBaseService channelBaseService = (ChannelBaseService) channelClasz.newInstance();
        channelBaseService.callService(txnInfo, orderInfo, channelCallCfg.getBizScene(), request);

        //交易成功更新商户累计限额
        mchntService.updateMchntTransLimit(mchntOrderInfoList);

        //应答信息
        StagePayResponse stagePayResponse = new StagePayResponse();
        stagePayResponse.setHeader(stagePayRequest.getHeader());
        UserOrderInfoMapper userOrderInfoMapper = new UserOrderInfoMapperImpl();
        userOrderInfo = userOrderInfoMapper.selectUserOrderInfoByPrimaryKey(instId, sysSeqNum);
        if (null != userOrderInfo) {
            stagePayResponse.setDiscountAmt(userOrderInfo.getRealDiscountAmt());
            stagePayResponse.setOrderAmt(userOrderInfo.getOrderAmt());
            stagePayResponse.setActualAmt(userOrderInfo.getRealPayAmt());
        }
        BizResponse<StagePayResponse> bizResponse = new BizResponse<>();
        bizResponse.setRspSysId(AppParamConstant.SYS_ID);
        bizResponse.setResult(stagePayResponse);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        return bizResponse;
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = new BizResponse();
        StagePayResponse stagePayResponse = (StagePayResponse) bizResponse.getResult();
        ConvertUtil.convertInput(stagePayResponse);
    }

    @Override
    public ChannelCallCfg channelCallSceneDiscern(Object request, List<ChannelCallCfg> channelCallCfgList) throws Exception {
        Optional<ChannelCallCfg> channelCallCfgOpt = channelCallCfgList.stream().filter(item ->
                item.getBizScene().equals(ShareParamConstant.CALL_CFG_DEFAULT_BIZ_SCENE)).findFirst();
        return channelCallCfgOpt.orElse(null);
    }

    @Override
    public CheckResultEnum channelCallPreCheck(Object request, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        StagePayRequest stagePayRequest = (StagePayRequest) request;
        String instId = stagePayRequest.getHeader().getInstId();
        String userId = stagePayRequest.getUserId();
        UserService userService = new UserServiceImpl();
        UserInfo userInfo = userService.getUserInfo(instId, userId, stagePayRequest.getHeader().getSession());
        SignAcctInfo signAcctInfo = (SignAcctInfo) GlobalTransUtil.getCacheValue(TransCacheConstant.SIGN_ACCT_INFO);
        /* 调用营销前生成营销用户集合(手机号、卡号、微信openId、支付宝userId等)，营销基于此信息判断用户是否可以享受营销 */
        if (ChannelEnum.MOMP.getChannelType().equals(channelCallCfg.getCallChannelId()) && "P01MO003".equals(channelCallCfg.getCallChannelTxn())) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("phoneNo", userInfo.getMobileNo());
            jsonObject.put("cardNo", Objects.requireNonNull(signAcctInfo).getSignAcctNo());
            /* 将用户信息放到交易缓存，同时将营销用户信息放到用户缓存中，便于付成功后优惠券信息查询和优惠券领取的接口调用时使用 */
            GlobalTransUtil.setCacheValue(TransCacheConstant.MOMP_USER_INFO, jsonObject.toJSONString());
            userService.setUserSessionValue(UserSessionConstant.MOMP_USER_ID, jsonObject.toJSONString());
        }
        return CheckResultEnum.PASSED;
    }

    @Override
    public TransStatusEnum channelCallResultProc(Object request, ChannelCallCfg channelCallCfg, TransStatusEnum transStatusEnum, Object channelResponse, OrderInfo needUpdateOrderInfo) throws Exception {
        StagePayRequest stagePayRequest = (StagePayRequest) request;
        //调用营销失败且客户使用卡卷时，则直接拒绝交易
        if (ChannelEnum.MOMP.getChannelType().equals(channelCallCfg.getCallChannelId()) && !TransStatusEnum.TRANS_SUCC.equals(transStatusEnum)) {
            if ("P01MO003".equals(channelCallCfg.getCallChannelTxn()) && null != stagePayRequest.getCouponInfo() &&
                    (null != stagePayRequest.getCouponInfo().getDiscountId() || null != stagePayRequest.getCouponInfo().getDiscountAmt())) {
                rglog.error("用户支付时有使用卡卷，调用营销失败，则整个交易失败!");
                throw new BizException(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
            }
        }
        return transStatusEnum;
    }
}
